package cn.yunhe.config;

import cn.yunhe.pojo.SysLog;
import cn.yunhe.service.ISysLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.validation.support.BindingAwareModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Component
@Aspect
public class LogAop {

    private Date visitTime;
    private Class<?> aClass;
    private Method method;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    ISysLogService sysLogService;

    /**
     * 需要获取到目标对象的所有
     *  类信息、方法信息（方法名、参数类型、参数名称）、请求地址信息
     * @param joinPoint
     *  封装的是目标对象的信息
     */
    @Before("execution(* cn.yunhe.controller.*.*(..))")
    public void before(JoinPoint joinPoint) throws NoSuchMethodException {
        //当前时间就是开始访问的时间
        visitTime = new Date();
        //获取目标对象的信息
        aClass = joinPoint.getTarget().getClass();
        //获取访问的方法名称
        String methodName = joinPoint.getSignature().getName();
        //获取参数信息
        Object[] args = joinPoint.getArgs();

        //根据参数的不同，获取方法的对象信息
        if(args == null || args.length == 0){//代表无参方法
            method = aClass.getMethod(methodName);
        } else{
            //获取参数的数据类型（都是类名.class）
            Class[] classArgs = new Class[args.length];
            for(int i=0;i<args.length;i++){
                //springMVC中有默认参数
                if(args[i].getClass() == BindingAwareModelMap.class){
                    classArgs[i] = Model.class;
                }else{
                    classArgs[i] = args[i].getClass();
                }
            }
            method = aClass.getMethod(methodName, classArgs);
        }
    }

    @After("execution(* cn.yunhe.controller.*.*(..))")
    public void after(JoinPoint joinPoint){
        //获取执行时长=开始访问的时间-结束的时间
        long excuteTime = new Date().getTime() - visitTime.getTime();

        String url = "";
        //获取访问的URL地址
        RequestMapping requestMapping = aClass.getAnnotation(RequestMapping.class);
        //注解中的地址@RequestMapping(value="/role/queryAll")
        String[] classValues = requestMapping.value();
        //获取方法上注解对应的请求地址
        RequestMapping annotation = method.getAnnotation(RequestMapping.class);
        if(annotation!=null){
            String[] methodValues = annotation.value();
            url = classValues[0]+methodValues[0];

            //获取IP地址
            String remoteAddr = request.getRemoteAddr();
            //获取Security的上下文对象来获取用户信息（用户的信息在登录时就已经存入到Security中）
            SecurityContext securityContext = SecurityContextHolder.getContext();
            User user = (User) securityContext.getAuthentication().getPrincipal();
            String username = user.getUsername();

            //将日志相关信息封装到SysLog对象
            SysLog sysLog = new SysLog();
            sysLog.setExecutionTime(excuteTime); //执行时长
            sysLog.setIp(remoteAddr);
            sysLog.setMethod("[类名] " + aClass.getName() + "[方法名] " + method.getName());
            sysLog.setUrl(url);
            sysLog.setUsername(username);
            sysLog.setVisitTime(visitTime);

            //将对象添加到数据库中
            sysLogService.insertLog(sysLog);
        }
    }
}
